package com.aispeech.rcprvd.utils;


import android.content.Context;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Build.VERSION;
import android.os.Build.VERSION_CODES;
import android.text.TextUtils;
import android.util.Log;

import java.util.HashMap;
import java.util.Map;

/**
 * @author rain  12.20 2018
 */

public class UsbCommUtils {

    private final static String TAG = "UsbCommUtils";

    public static UsbInterface getInterfaceByIndex(UsbDevice device, int index) {
        Log.d(TAG, "getInterfaceByIndex with: device = " + device + ", index = " + index + "");
        if (null == device) {
            return null;
        }
        int interfaceCount = device.getInterfaceCount();
        Log.d(TAG, "getInterfaceByIndex with: interfaceCount = " + interfaceCount);
        if (index < 0 || interfaceCount <= 0 || index > interfaceCount) {
            return null;
        }
        return device.getInterface(index);
    }

    public static UsbInterface getInterfaceByIndex(UsbDevice device, String index) {
        Log.d(TAG, "getInterfaceByIndex with: index = " + index + "");
        if (null == device || TextUtils.isEmpty(index)) {
            return null;
        }
//        int intIndex = -1;
        try {
            int intIndex = Integer.parseInt(index);
            return getInterfaceByIndex(device, intIndex);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static UsbInterface getStandardInterface(UsbDevice device) {
        Log.d(TAG, "getStandardInterface: ");
        if (null == device) {
            return null;
        }
        int indx = 0;
        for (int i = 0; i < device.getInterfaceCount(); i++) {
            UsbInterface usbInterface = device.getInterface(i);
            int interfaceClass = usbInterface.getInterfaceClass();
            Log.d(TAG, "getStandardInterface with: interfaceClass = " + interfaceClass + "");
            if (interfaceClass == UsbConstants.USB_CLASS_HID) {
//                return usbInterface;
                if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
                    Log.d(TAG, "getStandardInterface: usbInterface name  = " + usbInterface.getName());
                }

                if (indx == 1) {
                    //the standard in aispeech rule ,transfer interface is the second hid interface.
                    if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
                        Log.d(TAG, "getStandardInterface: select usbInterface name  = " + usbInterface.getName());
                    }
                    return usbInterface;
                } else {
                    indx++;
                }
            }
        }
        return null;
    }

    public static UsbInterface getInterfaceByAddr(UsbDevice device, String addr) {
        Log.d(TAG, "getInterfaceByAddr with:  addr = " + addr + "");
        if (null == device || TextUtils.isEmpty(addr)) {
            return null;
        }
        int intAddr = -1;
        try {
            intAddr = Integer.parseInt(addr);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        if (intAddr < 0) {
            return null;
        }
        for (int i = 0; i < device.getInterfaceCount(); i++) {
            UsbInterface usbInterface = device.getInterface(i);
            for (int j = 0; j < usbInterface.getEndpointCount(); j++) {
                UsbEndpoint endpoint = usbInterface.getEndpoint(j);
                if (endpoint.getAddress() == intAddr) {
                    return usbInterface;
                }
            }
        }
        return null;
    }

    public static UsbInterface getVendorInterface(UsbDevice device) {
        Log.d(TAG, "getVendorInterface : the interfaceClass is 0xFF");
        if (null == device) {
            return null;
        }
        for (int i = 0; i < device.getInterfaceCount(); i++) {
            UsbInterface usbInterface = device.getInterface(i);
            int interfaceClass = usbInterface.getInterfaceClass();
            Log.d(TAG, "getVendorInterface with: interfaceClass = " + interfaceClass + "");
            if (interfaceClass == UsbConstants.USB_CLASS_VENDOR_SPEC) {
                return usbInterface;
            }
        }
        return null;
    }

    public static UsbInterface getInterfaceByAddr(UsbDevice device, int addr) {
        Log.d(TAG, "getInterfaceByAddr with:  addr = " + addr + "");
        if (null == device || addr < 0) {
            return null;
        }

        for (int i = 0; i < device.getInterfaceCount(); i++) {
            UsbInterface usbInterface = device.getInterface(i);
            for (int j = 0; j < usbInterface.getEndpointCount(); j++) {
                UsbEndpoint endpoint = usbInterface.getEndpoint(j);
                if (endpoint.getAddress() == addr) {
                    return usbInterface;
                }
            }
        }
        return null;
    }

    public static UsbInterface getInterfaceByCSP(UsbDevice device, int clas, int subClass, int protocol) {
        Log.d(TAG, "getInterface with: device = " + device + ", cls = " + clas + ", subClass = " + subClass + ", protocol = " + protocol + "");
        if (null == device) {
            return null;
        }

        for (int i = 0; i < device.getInterfaceCount(); i++) {
            UsbInterface usbInterface = device.getInterface(i);
            if (clas != usbInterface.getInterfaceClass()
                    || subClass != usbInterface.getInterfaceSubclass()
                    || protocol != usbInterface.getInterfaceProtocol()) {
                continue;
            }
            return usbInterface;
        }
        return null;
    }


    public static UsbEndpoint getUsbEndpoint(UsbDevice device, String address) {
        Log.d(TAG, "getUsbEndpoint with: address = " + address + "");
        if (null == device || TextUtils.isEmpty(address)) {
            return null;
        }
        int intAddr = -1;
        try {
            intAddr = Integer.parseInt(address);
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
        if (intAddr < 0) {
            return null;
        }
        for (int i = 0; i < device.getInterfaceCount(); i++) {
            UsbInterface usbInterface = device.getInterface(i);
            for (int j = 0; j < usbInterface.getEndpointCount(); j++) {
                UsbEndpoint endpoint = usbInterface.getEndpoint(j);
                if (endpoint.getAddress() == intAddr) {
                    return endpoint;
                }
            }
        }
        return null;
    }

    public static UsbEndpoint getUsbEndpoint(UsbDevice device, int address) {
        Log.d(TAG, "getUsbEndpoint with: address = " + address + "");
        if (null == device || address < 0) {
            return null;
        }

        for (int i = 0; i < device.getInterfaceCount(); i++) {
            UsbInterface usbInterface = device.getInterface(i);
            for (int j = 0; j < usbInterface.getEndpointCount(); j++) {
                UsbEndpoint endpoint = usbInterface.getEndpoint(j);
                if (endpoint.getAddress() == address) {
                    return endpoint;
                }
            }
        }
        return null;
    }

    public static UsbDevice getUsbDevice(Context context, int vid, int pid) {
        Log.d(TAG, "getUsbDevice with: vid = " + vid + ", pid = " + pid + "");
        if (null == context || vid < 0 || pid < 0) {
            return null;
        }
        HashMap<String, UsbDevice> usbDeviceList = getUsbDeviceList(context);
        if (null == usbDeviceList) {
            return null;
        }
        if (!usbDeviceList.isEmpty()) {
            for (UsbDevice device : usbDeviceList.values()) {
                if (device.getVendorId() == vid && device.getProductId() == pid) {
                    return device;
                }
            }
        }
        return null;
    }

    public static boolean checkUsbDeviceConnect(UsbManager usbManager, UsbDevice device) {
        if (null != usbManager && null != device) {
            HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
            for (Map.Entry<String, UsbDevice> entry :
                    deviceList.entrySet()) {
                if (entry.getValue().getDeviceName().equals(device.getDeviceName())) {
                    return true;
                }
            }
        }
        return false;
    }

    public static HashMap<String, UsbDevice> getUsbDeviceList(Context context) {
        if (null == context) {
            return null;
        }
        UsbManager usbManager = getUsbManager(context);
        if (null == usbManager) {
            return null;
        }
        return usbManager.getDeviceList();
    }

    public static UsbManager getUsbManager(Context context) {
        if (null == context) {
            return null;
        }
        return (UsbManager) context.getSystemService(Context.USB_SERVICE);
    }

    /**
     * 可能是usb声卡吗
     *
     * @param device usb设备
     * @return ture  : 可能是 false : 不是
     */
    public static boolean maybeUsbSound(UsbDevice device) {
        int interfaceCount = device.getInterfaceCount();
        for (int interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++) {

//          USB class for audio devices = 1
//          USB class for communication devices = 2
//          USB class for human interface devices (for example, mice and keyboards) = 3
            UsbInterface usbInterface = device.getInterface(interfaceIndex);
            int interfaceClass = usbInterface.getInterfaceClass();
            if (interfaceClass == 1) {
                return true;
            }
        }
        return false;
    }

    public static String dumpDeviceInfo(UsbDevice device) {
        StringBuilder usbDeviceInfo = new StringBuilder();
        usbDeviceInfo.append("\n\n----------------- dumpDeviceInfo -----------------\n");
        if (null == device) {
            return "device is null";
        }
        usbDeviceInfo.append("\n\r vid=").append(device.getVendorId());
        usbDeviceInfo.append("\n\r pid=").append(device.getProductId());

        int interfaceCount = device.getInterfaceCount();
        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
            String serialNumber = device.getSerialNumber();
            usbDeviceInfo.append("\n\r serialNumber=").append(serialNumber);
        }
        usbDeviceInfo.append("\n\r interfaceCount = ").append(interfaceCount);
        for (int interfaceIndex = 0; interfaceIndex < interfaceCount; interfaceIndex++) {

            /**
             USB class for audio devices = 1
             USB class for communication devices = 2
             USB class for human interface devices (for example, mice and keyboards) = 3
             */

            UsbInterface usbInterface = device.getInterface(interfaceIndex);
            usbDeviceInfo.append("\n\rInterface class=").append(usbInterface.getInterfaceClass());
            if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
                usbDeviceInfo.append("\n\rInterface name=").append(usbInterface.getName());
            }

            usbDeviceInfo.append("\n\rInterfaceProtocol : ").append(usbInterface.getInterfaceProtocol());
            usbDeviceInfo.append("\n\rInterfaceSubclass : ").append(usbInterface.getInterfaceSubclass());

            for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
                UsbEndpoint ep = usbInterface.getEndpoint(i);

                /**
                 public static final int USB_ENDPOINT_XFER_CONTROL = 0;
                 public static final int USB_ENDPOINT_XFER_ISOC  = 1;
                 public static final int USB_ENDPOINT_XFER_BULK = 2;
                 public static final int USB_ENDPOINT_XFER_INT = 3;
                 */
                usbDeviceInfo.append("\n\rEndpoint: epType=").append(ep.getType()).append("; epDir=").append(ep.getDirection()).append("; epAddr=")
                        .append(ep.getAddress());
                /**
                 * out和in是针对Host来说的
                 */
                if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                    usbDeviceInfo.append("\n\rendpoint out: ").append(ep);
                } else {
                    usbDeviceInfo.append("\n\rendpoint in: ").append(ep);
                }
            }
        }
        return usbDeviceInfo.toString();
    }
}
